﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Manyor.Net
{
    /// <summary>
    /// 服务器端传输文件
    /// </summary>
    public class ServerFileTransfer : ICommand
    {
        #region -- Event --
        /// <summary>
        /// 文件传输开始
        /// </summary>
        public event EventHandler OnFileBeginTrans;
        /// <summary>
        /// 文件传输结束
        /// </summary>
        public event EventHandler OnFileTransComplate;
        /// <summary>
        /// 文件传输进度改变
        /// </summary>
        public event EventHandler OnFileTransProcessChanged;
        /// <summary>
        /// 文件传输错误
        /// </summary>
        public event EventHandler OnError;

        #endregion 

        private Action<byte[]> _sendAction;
        private FileStream fileStream;
        private string FileName;
        /// <summary>
        /// 文件保存路径
        /// </summary>
        public string FilePath { get; set; }
        /// <summary>
        /// 文件存放目录
        /// </summary>
        public string TransferFolder { get; set; }
        /// <summary>
        /// 构造器，
        /// </summary>
        /// <param name="sendAction">发送消息的委托</param>
        public ServerFileTransfer(Action<byte[]> sendAction)
        {
            _sendAction = sendAction;
        }

        /// <summary>
        /// 创建文件流
        /// </summary>
        /// <param name="bytes"></param>
        /// <param name="length"></param>
        protected void CreateFileStream(byte[] bytes, int length)
        {
            string fileName = System.Text.Encoding.UTF8.GetString(bytes, 
                                                                    NetConfig.HEADER_SIZE, 
                                                                  length - NetConfig.HEADER_SIZE);
            FileName=fileName;
            try
            {
                if (fileStream != null)
                {
                    fileStream.Close();
                }
            }
            catch
            {
                if (OnError != null)
                    OnError(null, null);
            }
            try
            {                
                fileStream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write);
                SocketHeader sh=new SocketHeader (){ CommandField=CommandCode.COMMAND_TRANSFER,
                    StatuField=CommandCode.CONNECT_TRANSFER_BEGIN};
                //创建文件后向对方发送就绪信号
                _sendAction(ByteUtility.SocketHeader(sh));
                //传输开始
                if (OnFileBeginTrans != null)
                    OnFileBeginTrans(null, null);
            }
            catch
            {
                //出错
                if (OnError != null)
                    OnError(null, null);
                throw new Exception("创建文件失败！");
            }        
        }

        /// <summary>
        /// 写入
        /// </summary>
        /// <param name="bytes"></param>
        /// <param name="length"></param>
        protected void AppendFileStream(byte[] bytes, int length)
        {
            SocketHeader sh = ByteUtility.ConvertHeader(bytes);
            //传输进度改变
            if (OnFileTransProcessChanged != null)
                OnFileTransProcessChanged(this, new FileEventArgs() { FileName = this.FileName, TransferedPercent = sh.ExtField / 100 });
            if (fileStream.CanWrite)
            {
                fileStream.Write(bytes, 
                                    NetConfig.HEADER_SIZE, 
                                    length - NetConfig.HEADER_SIZE);
            }
            //如果传输完毕，则关闭文件流
            if (sh.StatuField == CommandCode.CONNECT_TRANFSER_FINISH)
            {
                fileStream.Flush();
                fileStream.Close();
                //传输完毕
                if (OnFileTransComplate != null)
                {
                    OnFileTransComplate(null, null);
                }
            }

            SocketHeader response = new SocketHeader()
            {
                CommandField = CommandCode.COMMAND_TRANSFER,
                StatuField = CommandCode.CONNECT_TRANSFER_NEXT
            };
            //成功接收一个数据包后，发送反馈信号，指示可以继续发送
            _sendAction(ByteUtility.SocketHeader(response));
        }

        #region ICommand 成员

        public void ExecuteCommand(byte[] bytes, int length)
        {
            SocketHeader sh = ByteUtility.ConvertHeader(bytes);
            //接受指令
            if (sh.StatuField == CommandCode.CONNECT_TRANSFER_READY)
            {
                CreateFileStream(bytes, length);
            }
            //已经开始传送文件或最后一个数据包
            else if (sh.StatuField == CommandCode.CONNECT_TRANSFER_DOING || sh.StatuField == CommandCode.CONNECT_TRANFSER_FINISH)
            {
                AppendFileStream(bytes, length);
            }
        }

        #endregion
    }
}
